iT邦幫忙

2021 iThome 鐵人賽

DAY 11
1
Arm Platforms

基於ARM-M0架構MCU之落摔檢測韌體開發系列 第 11

[DAY 11] _軟體實現I2C協議以三軸感測器為例 (ADXL345)

  • 分享至 

  • xImage
  •  

昨天DAY10講了控制GPIO口來完成協議,今天來講實際的例子,以大家最常聽過三軸感測器為例,首先介紹一下這個感測器,ADXL345 是一款低功耗三軸加速度計,非常適合移動設備應用,可以在傾斜檢測應用中測量靜態重力加速度,還可以測量動態加速度,也可檢測自由落體。

昨天說了這兩個函式(bdp_I2C_GPIO.c和bdp_I2C_GPIO.h),今天就來講解如何利用昨天寫的函式來讀取三軸感測器,
先講解我的bdp_I2C_ADXL345.h
首先,我先附上Datasheet網址:
https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf (英文版本)
https://www.analog.com/media/cn/technical-documentation/data-sheets/ADXL345_cn.pdf (簡體翻譯版本)
接下我會搭配這個手冊做部分講解,當然這手冊有中文版本了是大陸翻譯的,我不建議只看中文的,有可能會有錯誤,真的看不懂可以交叉著看,畢竟這是一間大公司ANALOG DEVICES寫出來的手冊,我是相信不會有問題,有問題就不會出產這顆感測器了。

bdp_I2C_ADXL345.h

#ifndef __BSP_I2C_adxl_H
#define __BSP_I2C_adxl_H

#include "bsp_I2C_gpio.h"

#define DEVICE_ID       0X00    //器件ID,0XE5
#define THRESH_TAP      0X1D    //敲擊閥值
#define OFSX            0X1E
#define OFSY            0X1F
#define OFSZ            0X20
#define DUR             0X21
#define Latent          0X22
#define Window          0X23 
#define THRESH_ACK      0X24
#define THRESH_INACT    0X25 
#define TIME_INACT      0X26
#define ACT_INACT_CTL   0X27     
#define THRESH_FF       0X28    
#define TIME_FF         0X29 
#define TAP_AXES        0X2A  
#define ACT_TAP_STATUS  0X2B 
#define BW_RATE         0X2C 
#define POWER_CTL       0X2D 
#define INT_ENABLE      0X2E
#define INT_MAP         0X2F
#define INT_SOURCE      0X30
#define DATA_FORMAT     0X31
#define DATA_X0         0X32
#define DATA_X1         0X33
#define DATA_Y0         0X34
#define DATA_Y1         0X35
#define DATA_Z0         0X36
#define DATA_Z1         0X37
#define FIFO_CTL        0X38
#define FIFO_STATUS     0X39

//如果ALT ADDRESS脚(12脚)接地,ADXL設備地址為0X53(不包含最低位).
//如果接V3.3,则ADXL設備地址为0X1D(不包含最低位).
//如果Pin12腳接3.3V,为0X3B和0X3A,如果接GND,則為0XA7和0XA6
#define ADXL_READ    0XA7			//二進制為 1010 0111
#define ADXL_WRITE   0XA6			//二進制為 1010 0110

uint8_t ADXL345_Init(void);                         //初始化ADXL345
void ADXL345_WR_Reg(uint8_t addr,uint8_t val);      //Write_ADXL345寄存器
uint8_t ADXL345_RD_Reg(uint8_t addr);               //Read_ADXL345寄存器

首先會define這麼多東西是因為,我把手冊上所有可操作的暫存器位址都記下來了,當然我這邊沒有全部使用到,可以看以下手冊第23頁的部分:
https://ithelp.ithome.com.tw/upload/images/20210924/20141979YJcVWJEOpN.png
可以看到上圖我紅框的部分,這是三個軸讀取的暫存器位置部分,這個每個腳位都有對應詳細功能說明,在手冊接下去24頁後的部分,最後幾行是函式的宣告,再來講解bdp_I2C_ADXL345.c

bdp_I2C_ADXL345.c

uint8_t ADXL345_Init(void)
{ 
//初始化IIC
 GPIO_InitTypeDef GPIO_InitStructure;
 RCC_AHBPeriphClockCmd(I2C_GPIO_CLK, ENABLE);	/* 打開GPIO時鐘 */
 GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;  	
 GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;  	/* 開漏輸出 */
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
 /* 給一個停止信號, 重定I2C匯流排上的所有設備到待機模式 */
 i2c_Stop();     
	//------------------------------------------------
	if(ADXL345_RD_Reg(DEVICE_ID)==0XE5) //ID
	{
	ADXL345_WR_Reg(DATA_FORMAT,0X2B);  //**0x31** 低電平中斷輸出,13位元全解析度,輸出資料右對齊,16g量程
	ADXL345_WR_Reg(BW_RATE,0x0A);       //**0x2C** 資料輸出速度為400Hz				
	ADXL345_WR_Reg(POWER_CTL,0x28);     //**0X2D** 連結使能,測量模式
	ADXL345_WR_Reg(INT_ENABLE,0x00);    //不使用中斷 
	//*******偏移寄存器**************		
	ADXL345_WR_Reg(OFSX,0x00);			//00  X=FB,Y=0xF9 ___ //98 X=00,Y=FE,Z=EE
	ADXL345_WR_Reg(OFSY,0x00);			//算法   1LSB=15.6mg
	ADXL345_WR_Reg(OFSZ,0x00);  		//先算偏移多少個LSB在,用2's表示負號
	return 0;
	}
  return 1;                                     
}

這是ADXL345的初始化函式,先對GPIO口的初始化,再來設定感測的模式ADXL345_WR_Reg為對暫存器寫數值,至於要寫數值手冊24頁後有說,這邊先不詳談,等說完這整個配置我再詳細講解,ADXL345_RD_Reg是對暫存器讀取數值
接下面是寫暫存和讀取暫存器出來的數值函式

//寫ADXL345寄存器	  addr:暫存器地址		al:要寫入的值
void ADXL345_WR_Reg(uint8_t addr,uint8_t val)  //void ADXL345_write(u8 addr, u8 data)
{
	i2c_Start();                 
	i2c_SendByte(ADXL_WRITE);   
	i2c_WaitAck();    
	i2c_SendByte(addr);
	i2c_WaitAck();                                                         
	i2c_SendByte(val);                                
	i2c_WaitAck();                    
	i2c_Stop();                     
	
} 
//讀ADXL345寄存器		addr:寄存器地址		返回值:讀到的值
uint8_t ADXL345_RD_Reg(uint8_t addr)
{
	uint8_t temp=0;  
	i2c_Start();                   
	i2c_SendByte(ADXL_WRITE);      
	i2c_WaitAck();       
	i2c_SendByte(addr);        //發送寄存器地址
	i2c_WaitAck();                                                       
	i2c_Start();               
	i2c_SendByte(ADXL_READ);       
	i2c_WaitAck();        
	temp=i2c_ReadByte();       
	i2c_NAck();
	i2c_Stop();                      
	return temp;              
} 

至於這時需如何觀看手冊寫入時序,我明天會再一步步講解搭配手冊講解

然後main.c可以來使用這些函式讀值啦~,附上我的主程式

#include "bsp_I2C_adxl345.h"
#include "bsp_SysTick.h"  //操作MO內核暫存器使用滴答計時器來做精準計時
                          //參考網站:https://kknews.cc/zh-tw/news/96p52m5.html
int main(void)
{
  int8_t x0,x1,y0,y1,z1,z0;//宣告3個軸的變數,1個軸有高8為和低8位
  SysTick_Init(48);        //配置Delay函式
  
  DEBUG_USART_Config();    //初始化UART
  ADXL345_Init();          //初始化ADXL345
  
  while(1)
  {
    x0=ADXL345_RD_Reg(0xAA);// 取得 X 軸 低位元資料
	x1=ADXL345_RD_Reg(0x33);// 取得 X 軸 高位元資料
	x=(((short)(x1 << 8)+x0)/256.0);
    
	y0=ADXL345_RD_Reg(0x34);// 取得 Y 軸 低位元資料
    y1=ADXL345_RD_Reg(0x35);// 取得 Y 軸 高位元資料
    y=(((short)(y1 << 8)+y0)/256.0);
    
    z0=ADXL345_RD_Reg(0x36);// 取得 Z 軸 低位元資料
    z1=ADXL345_RD_Reg(0x37);// 取得 Y 軸 高位元資料
    z=(((short)(z1 << 8)+z0)/256.0);
    
	printf("X=%.3f  Y=%.3f  Z=%.3f\r\n",x,y,z);
	delay_ms(100);
   }
}

以上看到的寫法,明天會再搭配手冊慢慢講解,想學嵌入式學看datasheet(數據手冊)是必經之路~~
可以先自己看看,我想信很多人都看的我這再寫什麼...,最後一行的printf是利用寫好的函是讓UART傳出數值,這樣我就可以用串口視窗來查看三個軸的數值啦~~~


上一篇
[DAY 10] _軟體實現I2C協議
下一篇
[DAY 12] _三軸感測器讀取函示講解 (ADXL345)
系列文
基於ARM-M0架構MCU之落摔檢測韌體開發35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言